JavaScript 设计模式之状态模式

Author Avatar
Klein 8月 29, 2018

介绍

  • 一个对象有状态
  • 每次状态变化都会触发一个逻辑
  • 不能总是用 if…else

演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class State {
constructor(color) {
this.color = color
}
handle(context) {
console.log(`turn to ${this.color} light`);
context.setState(this)
}
}

// 主体
class Context {
constructor() {
this.state = null
}
getState() {
return this.state
}
setState(state) {
this.state = state
}
}

// 测试
let context = new Context()

let green = new State('green')
let yellow = new State('yellow')
let red = new State('red')

green.handle(context)
console.log(context.getState());

场景

  • 有限状态机
    使用开源库: javascript-state-machine
1
<button id="btn1"></button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import StateMachine from 'javascript-state-machine'
var fsm = new StateMachine({
init: '收藏'
transitions: [
{
name: 'doStore',
from: '收藏'
to: '取消收藏'
},
{
name: 'deleteStore',
from: '取消收藏'
to: '收藏'
}
],
methods: {
// 监听执行收藏
onDoStore: function () {
console.log('收藏成功');
},

// 监听取消收藏
onDeleteStore: function () {
console.log('已经取消收藏');
updateText()
}
}

})

// let btn = document.getElementsById('btn1')
let $btn = $('#btn1')

$btn.click(function () {
if (fsm.is('收藏')) {
fsm.doStore()
} else {
fsm.deleteStore()
}
})

// 更新按钮文章
function updateText() {
$btn.text(fsm.state)
}

// 初始化文案
updateText()
  • 写一个简单的 Promise
    Promise 是一个有限状态机,有以下三种状态
  • pending
  • fullfilled
  • rejected
    状态的变化只有两种:
  • pending -> fullfilled
  • pending -> rejected
    而且状态不可逆
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    import StateMachine from 'javascript-state-machine'

    // 状态机模型
    let fsm = new StateMachine({
    // 初始化状态
    init: 'pending',

    transitions: [
    {
    name: 'resolve',
    from: 'pending',
    to: 'fullfilled'
    },
    {
    name: 'reject',
    from: 'pending',
    to: 'rejected'
    }
    ],
    methods: {
    // 监听 resolve
    onResolve: function (state, data) {
    data.successList.forEach(fn => fn())
    },

    // 监听 reject
    onReject: function (state, data) {
    data.failList.forEach(fn => fn())
    }
    }
    })

    class MyPromise {
    constructor(fn) {
    this.successList = []
    this.failList = []

    fn(() => {
    fsm.resolve(this)
    }, () => {
    fsm.reject(this)
    })
    }
    then(succesFn, failFn) {
    this.successList.push(succesFn)
    this.failList.push(failFn)
    }
    }

    // 测试
    function loadImg(src) {
    const promise = new Promise(function(resolve, reject) {
    let img = document.createElement('img')
    img.onload = function () {
    resolve(img)
    }
    img.onerror = function (e) {
    reject(e)
    }
    img.src = src
    })
    return promise
    }
    let src = ''
    let result = loadImg(src)

    result.then(function() {
    console.log('ok1');
    }, function() {
    console.log('fail1');
    })
    result.then(function() {
    console.log('ok2');
    }, function() {
    console.log('fail2');
    })

设计原则验证

  • 将状态对象和主题对象分离,状态的变化逻辑单独处理
  • 符合开放封闭原则